package com.bagus.mediapipefacedetection.module.detect;

import android.graphics.SurfaceTexture;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.KeyEvent;
import android.view.TextureView;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;


import com.bagus.mediapipefacedetection.R;
import com.bagus.mediapipefacedetection.camera.CameraFactory;
import com.bagus.mediapipefacedetection.constant.ErrorType;
import com.bagus.mediapipefacedetection.listener.ResultEntity;
import com.bagus.mediapipefacedetection.module.base.BaseActivity;
import com.bagus.mediapipefacedetection.quality.DetectQualityStatus;
import com.bagus.mediapipefacedetection.utils.IMediaPlayer;
import com.bagus.mediapipefacedetection.utils.Screen;
import com.bagus.mediapipefacedetection.view.CameraTextureView;

import java.lang.ref.WeakReference;


public class DetectActivity extends BaseActivity<DetectPresenter> implements DetectContract.View, TextureView.SurfaceTextureListener {
    private static final String TAG = "DetectActivity";
    private TextView tvStatics;
    private CameraTextureView mTextureView;
    private SurfaceTexture mSurfaceTexture = null;
    private IMediaPlayer mIMediaPlayer;
    private TextView    mTvTips = null;
    private Button mBtnBack = null;
    private Button mBtnSwitch = null;
    private ImageView mImgFace = null;

    private MyHandler mHandler = null;
    private boolean openCameraResult = false;

    private final static int HANDLE_WHAT_REDRAW_TEXTUREVIEW = 100;
    private final static int HANDLE_WHAT_SET_TIPS = 105;
    private final static int HANDLE_WHAT_INIT_FINISH = 113;
    private final static int HANDLE_WHAT_SHOW_STATICS = 116;

    private final static String PHONE_HONOR = "FRD-AL10";

    @Override
    public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
        mSurfaceTexture = surface;
        getPresenter().startPreview();
    }

    @Override
    public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {

    }

    @Override
    public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
        //try to fix BufferQueue has been abandoned
        try {
            getPresenter().stopPreview();
            getPresenter().closeCamera();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {

    }

    @Override
    protected void initView() {
        mTextureView = (CameraTextureView) findViewById(R.id.layout_textureview);
        mTextureView.setSurfaceTextureListener(this);
        mTextureView.setVisibility(View.VISIBLE);

        tvStatics = findViewById(R.id.statics_info);
        mTvTips = (TextView) findViewById(R.id.tv_tips);
        mBtnBack = findViewById(R.id.btn_back);
        mBtnBack.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                exit(ErrorType.MGFacePPSkinAICameraErrorUserCancel, null);
            }
        });
        mBtnSwitch = findViewById(R.id.btn_switch);
        mBtnSwitch.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        getPresenter().switchCamera();
//                        checkCamera();
                    }
                }).start();
            }
        });
        mImgFace = findViewById(R.id.img_face);
        mImgFace.post(new Runnable() {
            @Override
            public void run() {
                adjustFaceImageSize();
            }
        });

        mHandler = new MyHandler(this);
    }

    private void openCamera() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                openCameraResult = getPresenter().openCamera();
                if (openCameraResult) {
//                    checkCamera();
                } else {

                }
            }
        }).start();
    }

    private void checkCamera() {
        if (openCameraResult && mSurfaceTexture != null) {
            if (getPresenter().startPreview()) {
                Bundle bundle = new Bundle();
                bundle.putInt("cameraWidth", CameraFactory.mWidth);
                bundle.putInt("cameraHeight", CameraFactory.mHeight);
                sendHanderMessage(HANDLE_WHAT_REDRAW_TEXTUREVIEW, bundle);
            } else {

            }
        }
    }

    private boolean isDestroyed = false;

    private void destroy() {
        if (isDestroyed) {
            return;
        }
        getPresenter().stopDetect();
        getPresenter().closeCamera();
        getPresenter().detach();
        if (mHandler != null) {
            mHandler.removeCallbacksAndMessages(null);
        }

        isDestroyed = true;
    }

    @Override
    protected void onPause() {
        if (mIMediaPlayer != null) {
            mIMediaPlayer.close();
        }
        if (!isFinishing()) {
//            RouterImpl.getInstance().onExit(ErrorType.MGFacePPSkinAICameraErrorBackGround, null);
        }
        if (isFinishing()) {
            destroy();
        }
        super.onPause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        mIMediaPlayer = new IMediaPlayer(this);
        openCamera();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        destroy();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            finish();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    @Override
    protected int getLayoutResId() {
        return R.layout.activity_detect;
    }

    @Override
    protected void initData() {
    }

    @Override
    protected DetectPresenter createPresenter() {
        return new DetectPresenter();
    }

    @Override
    public SurfaceTexture getSurfaceTexture() {
        return mSurfaceTexture;
    }

    @Override
    public void initFinish() {
        sendHanderMessage(HANDLE_WHAT_INIT_FINISH, new Bundle());
    }

    @Override
    public void setUserTips(int tipsType) {
        Bundle data = new Bundle();
        data.putInt("tipsType", tipsType);
        sendHanderMessage(HANDLE_WHAT_SET_TIPS, data);
    }

    @Override
    public void showStatics(String statics) {
        Bundle data = new Bundle();
        data.putString("statics", statics);
        sendHanderMessage(HANDLE_WHAT_SHOW_STATICS, data);
    }

    @Override
    public void showLoadingProgress() {

    }

    @Override
    public void cameraOpened() {
        Bundle bundle = new Bundle();
        bundle.putInt("cameraWidth", CameraFactory.mWidth);
        bundle.putInt("cameraHeight", CameraFactory.mHeight);
        sendHanderMessage(HANDLE_WHAT_REDRAW_TEXTUREVIEW, bundle);
    }

    @Override
    public void detectFinish(ErrorType errorType, ResultEntity result) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                showTips(DetectQualityStatus.MGFacePPSkinAICameraFaceFinish.ordinal());
            }
        });
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                exit(errorType, result);
            }
        }, 1000);
    }

    @Override
    public void onExit(ErrorType errorType, ResultEntity result) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                exit(errorType, result);
            }
        });
    }

    private void exit(ErrorType errorType, ResultEntity result) {
//        RouterImpl.getInstance().onExit(errorType, result);
        finish();
    }

    private void sendHanderMessage(int what, Bundle data) {
        Message msg = new Message();
        msg.what = what;
        msg.setData(data);
        mHandler.sendMessage(msg);
    }

    private void adjustFaceImageSize() {
        float scale = 0.85f;
        float scaleImg = mImgFace.getHeight() / (mImgFace.getWidth() * 1.0f);
        int imageWidth = (int) (Screen.mWidth * scale);
        int imageHeight = (int) (imageWidth * scaleImg);
        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mImgFace.getLayoutParams();
        layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
        layoutParams.width = imageWidth;
        layoutParams.height = imageHeight;
        mImgFace.setLayoutParams(layoutParams);
    }
    
    private void adjustTextureViewSize(int cameraWidth, int cameraHeight) {
        if (PHONE_HONOR.equals(Build.MODEL)) {
            return;
        }
        float scale = Math.max(Screen.mHeight * 1.0f / cameraWidth, Screen.mWidth * 1.0f / cameraHeight);
        int layout_width = (int) (cameraHeight * scale);
        int layout_height = (int) (cameraWidth * scale);

        mTextureView.refreshView(layout_width, layout_height);

        RelativeLayout.LayoutParams surfaceParams = (RelativeLayout.LayoutParams) mTextureView.getLayoutParams();
        int topMargin = Math.min((Screen.mHeight - layout_height) / 2, 0);
        int leftMargin = Math.min((Screen.mWidth - layout_width) / 2, 0);
        surfaceParams.topMargin = topMargin;
        surfaceParams.leftMargin = leftMargin;
        mTextureView.setLayoutParams(surfaceParams);
    }

    private int lastTipsResId = -1;
    private void showTips(int tips) {
        String statusTips = null;
        int tipsResId = -1;
        if (tips == DetectQualityStatus.MGFacePPSkinAICameraFaceNone.ordinal()) {
          return;
        }
        if (tips == DetectQualityStatus.MGFacePPSkinAICameraFaceNotFound.ordinal()) {
            statusTips = getResources().getString(R.string.face_quality_tips_face_not_found);
            tipsResId = R.raw.tips_no_face;
        }else if (tips == DetectQualityStatus.MGFacePPSkinAICameraFaceTooLarge.ordinal()) {
            statusTips = getResources().getString(R.string.face_quality_tips_too_large);
            tipsResId = R.raw.tips_too_near;
        }else if (tips == DetectQualityStatus.MGFacePPSkinAICameraFaceTooSmall.ordinal()) {
            statusTips = getResources().getString(R.string.face_quality_tips_too_small);
            tipsResId = R.raw.tips_too_far;
        }else if (tips == DetectQualityStatus.MGFacePPSkinAICameraFaceNeedLeft.ordinal()) {
            statusTips = getResources().getString(R.string.face_quality_tips_need_left);
            tipsResId = R.raw.tips_need_left;
        }else if (tips == DetectQualityStatus.MGFacePPSkinAICameraFaceNeedRight.ordinal()) {
            statusTips = getResources().getString(R.string.face_quality_tips_need_right);
            tipsResId = R.raw.tips_need_right;
        }else if (tips == DetectQualityStatus.MGFacePPSkinAICameraFaceNeedTop.ordinal()) {
            statusTips = getResources().getString(R.string.face_quality_tips_need_top);
            tipsResId = R.raw.tips_need_top;
        }else if (tips == DetectQualityStatus.MGFacePPSkinAICameraFaceNeedBottom.ordinal()) {
            statusTips = getResources().getString(R.string.face_quality_tips_need_bottom);
            tipsResId = R.raw.tips_need_bottom;
        }else if (tips == DetectQualityStatus.MGFacePPSkinAICameraFaceAlignCenter.ordinal()) {
            statusTips = getResources().getString(R.string.face_quality_tips_align_center);
            tipsResId = R.raw.tips_align_center;
        }else if (tips == DetectQualityStatus.MGFacePPSkinAICameraFaceKeepOutEye.ordinal()) {
            statusTips = getResources().getString(R.string.face_quality_tips_keep_out_eye);
            tipsResId = R.raw.tips_keep_out_eye;
        }else if (tips == DetectQualityStatus.MGFacePPSkinAICameraFaceKeepOutMouth.ordinal()) {
            statusTips = getResources().getString(R.string.face_quality_tips_keep_out_mouth);
            tipsResId = R.raw.tips_keep_out_mouth;
        }else if (tips == DetectQualityStatus.MGFacePPSkinAICameraFaceCloseEyes.ordinal()) {
            statusTips = getResources().getString(R.string.face_quality_tips_close_eyes);
            tipsResId = R.raw.tips_close_eye;
        }else if (tips == DetectQualityStatus.MGFacePPSkinAICameraFaceKeeping.ordinal()) {
            statusTips = getResources().getString(R.string.face_quality_tips_keeping);
            tipsResId = R.raw.tips_keeping;
        }else if (tips == DetectQualityStatus.MGFacePPSkinAICameraFaceFinish.ordinal()) {
            statusTips = getResources().getString(R.string.face_quality_tips_finish);
            tipsResId = R.raw.tips_well_done;
        }
        mTvTips.setText(statusTips);
        if (lastTipsResId != tipsResId) {
            mIMediaPlayer.doPlay(tipsResId);
            mIMediaPlayer.setOnCompletionListener(tipsResId, true);
        }
        lastTipsResId = tipsResId;
    }

    private static class MyHandler extends Handler {
        private final WeakReference<DetectActivity> mActivity;

        public MyHandler(DetectActivity activity) {
            this.mActivity = new WeakReference<DetectActivity>(activity);
        }

        @Override
        public void handleMessage(@NonNull Message msg) {
            DetectActivity activity = mActivity.get();
            super.handleMessage(msg);
            if (activity != null) {
                switch (msg.what) {
                    case HANDLE_WHAT_REDRAW_TEXTUREVIEW:
                        Bundle data = msg.getData();
                        int cameraHeight = data.getInt("cameraHeight");
                        int cameraWidth = data.getInt("cameraWidth");
                        activity.adjustTextureViewSize(cameraWidth, cameraHeight);
                        break;
                    case HANDLE_WHAT_SET_TIPS:
                        Bundle tipsData = msg.getData();
                        int tipsType = tipsData.getInt("tipsType");
                        activity.showTips(tipsType);
                        break;
                    case HANDLE_WHAT_INIT_FINISH:
                        activity.getPresenter().startDetect();
                        break;
                    case HANDLE_WHAT_SHOW_STATICS:
                        Bundle staticsData = msg.getData();
                        String statics = staticsData.getString("statics");
                        activity.tvStatics.setText(statics);
                        break;
                    default:
                        break;
                }
            }
        }
    }
}
